//
//  objc_msgSend.h
//  面试题
//
//  Created by Toj on 8/13/21.
//

blog: https://www.jianshu.com/p/d070b2087a01

#pragma mark - 发送消息
消息发送, 类调用方法
3步骤
1. 消息查找 & 调用
1.1 缓存列表查找
1.2 类内方法列表找
1.3 父类方法列表找
1.4 重复【1.3】
2. 消息转发
2.1 动态解析
2.2 重定向 -> 可以多个转发
2.3 方法签名
2.4 消息转发 -> 单1转发
2.5 系统报错

#pragma mark - 1. 消息查找 & 调用
[id method]
1.1 编译器编译的时候会把method 包装成sel
1.2 运行时调用 objc_msgSend(id, sel) 汇编实现
1.3 查找: 根据id内的isa指针 能找到Class(类对象)
1.3.1 首先在当前类内的cache hash table里找, 找到对应的IMP就调用返回, 找不到就【1.3.2】
1.3.1.1 hash操作: 把sel做hash参数
// hash表能提高函数查找速度
hash算法: `h(x) = (x >> shift) & mask`
`shift & mask`: 通过回溯算法多次查找, 最后找不到会删除类不为生成IMP缓存
1.3.1.2 通过hash得到的key在hash table中找到IMP
1.3.2 接着在当前类methodList找, 找到对应的IMP就调用, 加到cache hash table
里,
然后返回, 找不到就【1.3.3】
1.3.3 当前类内没有找到就去父类找,
根据superclass指针找到父类重复【1.3.1操作】
1.3.4 最后到根类仍然找不到, 返回一个_objc_msgForward指针做消息转发

#pragma mark - 2. 消息转发
2.1 动态解析,
// 解析类方法
+ resolveClassMethod(sel)
{
    BOOL result = [super resolveInstanceMethod:sel];
    if (!result) {
        id c = object_getClass(self);
        result = class_addMethod(c, sel, (IMP)eat2, "v@:");
    }
    return result;
}
// 解析实例方法
+ resolveInstanceMethod(sel)
{
    BOOL result = [super resolveInstanceMethod:sel];
    if (!result) {
        result = class_addMethod(self, sel, (IMP)eat, "v@:");
    }
    return result;
}

可以判断这个sel是否存在, 存在直接返回
不存在, 可以解析成另外一个方法

2.2 消息转发: 重定向, 备用的接受者
// 为sel做目标转发
- forwardingTargetForSelector(sel)
{
    id result = [super forwardingTargetForSelector:aSelector];
    if (!result) {
        TTCar *car = [TTCar new];
        return car;
    }
    return result;
}

2.3 为SEL做消息签名
- (NSMethodSignature)methodSignatureForSelector(sel)
{
    NSMethodSignature *sig = [[TTCar class] instanceMethodSignatureForSelector:aSelector];
    return sig;
}

2.4 多次转发, 可以转发给多个对象
- forwardInvocation(invocation)
{
    [anInvocation invokeWithTarget:[TTCar new]];
}

2.5 最终的报错
- doesNotRecognizeSelector(sel)
{
    
}

#pragma mark - 3. 底层实现
查看文件:
objc_msgSend底层实现.h
_objc_msgForward.h
